File: /var/www/html/dashboard.orbiwheels.com/vendor/cuyz/valinor/src/Cache/FileSystemCache.php
<?php
declare(strict_types=1);
namespace CuyZ\Valinor\Cache;
use CuyZ\Valinor\Cache\Exception\CacheDirectoryNotWritable;
use CuyZ\Valinor\Cache\Exception\CompiledPhpCacheFileNotWritten;
use CuyZ\Valinor\Cache\Exception\CorruptedCompiledPhpCacheFile;
use Error;
use FilesystemIterator;
use function bin2hex;
use function file_exists;
use function file_put_contents;
use function is_dir;
use function mkdir;
use function random_bytes;
use function rename;
use function rmdir;
use function str_contains;
use function umask;
use function unlink;
/**
* @api
*
* @template EntryType
* @implements Cache<EntryType>
*/
final class FileSystemCache implements Cache
{
private const GENERATED_MESSAGE = 'Generated by ' . self::class;
public function __construct(
private string $cacheDir,
) {}
/** @internal */
public function get(string $key, mixed ...$arguments): mixed
{
$filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php';
if (! file_exists($filename)) {
return null;
}
try {
return (require $filename)(...$arguments); // @phpstan-ignore callable.nonCallable
} catch (Error) {
throw new CorruptedCompiledPhpCacheFile($filename);
}
}
/** @internal */
public function set(string $key, CacheEntry $entry): void
{
$tmpDir = $this->cacheDir . DIRECTORY_SEPARATOR . '.valinor.tmp';
$filename = $this->cacheDir . DIRECTORY_SEPARATOR . $key . '.php';
if (! is_dir($tmpDir) && ! @mkdir($tmpDir, 0777, true)) {
throw new CacheDirectoryNotWritable($this->cacheDir);
}
/** @infection-ignore-all */
$tmpFilename = $tmpDir . DIRECTORY_SEPARATOR . bin2hex(random_bytes(16));
try {
$code = '<?php // ' . self::GENERATED_MESSAGE . PHP_EOL . "return $entry->code;" . PHP_EOL;
if (! @file_put_contents($tmpFilename, $code)) {
throw new CompiledPhpCacheFileNotWritten($tmpFilename);
}
if (! @rename($tmpFilename, $filename)) {
throw new CompiledPhpCacheFileNotWritten($filename);
}
@chmod($filename, 0666 & ~umask());
} finally {
@unlink($tmpFilename);
}
}
public function clear(): void
{
if (! is_dir($this->cacheDir)) {
return;
}
$shouldDeleteRootDir = true;
/** @var FilesystemIterator $file */
foreach (new FilesystemIterator($this->cacheDir) as $file) {
if ($file->getFilename() === '.valinor.tmp') {
@rmdir($file->getPathname());
continue;
}
if (! $file->isFile()) {
$shouldDeleteRootDir = false;
continue;
}
$line = $file->openFile()->getCurrentLine();
if (! $line || ! str_contains($line, self::GENERATED_MESSAGE)) {
$shouldDeleteRootDir = false;
continue;
}
@unlink($file->getPathname());
}
if ($shouldDeleteRootDir) {
@rmdir($this->cacheDir);
}
}
}